package com.padgett.resourcemanagement.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.logging.Logger;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Text;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.labs.repackaged.org.json.JSONException;
import com.google.appengine.labs.repackaged.org.json.JSONObject;
import com.padgett.resourcemanagement.data.ClientDAO;

/**
 * Save client.
 * 
 * @author andyleung
 * 
 */
@SuppressWarnings("serial")
public class AjaxSaveClientServicesServlet extends HttpServlet{
	private static final Logger logger=Logger.getLogger(AjaxSaveClientServicesServlet.class.getName());
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		String clientId=req.getParameter("clientId");
		String clientName=req.getParameter("clientName");
		String type=req.getParameter("Type");
		String dueDateString=req.getParameter("DueDate");
		String fee=req.getParameter("Fee");
		String billableString=req.getParameter("Billable");
		String times=req.getParameter("Times");
		String repeat=req.getParameter("Repeat");
		String untilString=req.getParameter("Until");
		String accountant=req.getParameter("Accountant");
		String note=req.getParameter("Note");
		// Client Number and Legal Number must be presented to generate a unique key
		UserService userService=UserServiceFactory.getUserService();
		User user=userService.getCurrentUser();
		Key clientKey=KeyFactory.stringToKey(clientId);
		if(clientId==null||clientId.isEmpty()){
			resp.getWriter().write("{\"success\":false,\"error\":\"Invalid client\"}");
		}else{
			List<Entity> services=new ArrayList<Entity>();
			boolean billable=(billableString.equalsIgnoreCase("true")?true:false);
			if(times!=null&&!times.isEmpty()&&Integer.parseInt(times)==1){
				Date dueDate=new Date(Long.parseLong(dueDateString));
				Key key=new KeyFactory.Builder(clientKey)
				.getKey();
				Entity service=new Entity("Service",key);
				service.setUnindexedProperty("CreatedBy", user.getNickname());
				service.setUnindexedProperty("CreatedDate", new Date(System.currentTimeMillis()));
				service.setUnindexedProperty("LastModifiedBy", user.getNickname());
				service.setUnindexedProperty("LastModifiedDate", new Date(System.currentTimeMillis()));
				service.setProperty("Client", clientKey);
				service.setProperty("Billed", Boolean.FALSE);
				service.setProperty("Type", type);
				service.setProperty("Billable", billable);
				service.setProperty("Completed", false);
				service.setUnindexedProperty("Fee", Double.parseDouble(fee));
				service.setProperty("Accountant", accountant);
				if(note!=null){
					service.setUnindexedProperty("Note", new Text(note));
				}
				service.setProperty("DueDate", dueDate);
				services.add(service);
			}else{
				if(untilString!=null&&!untilString.isEmpty()){
					Date tempDate=new Date(Long.parseLong(dueDateString));
					GregorianCalendar nextDate=new GregorianCalendar();
					nextDate.setTime(tempDate);
					Date until=new Date(Long.parseLong(untilString));
					GregorianCalendar untilDate=new GregorianCalendar();
					untilDate.setTime(until);
					// Ensure until is after today.
					if(until.after(new Date(System.currentTimeMillis()))){
						boolean uptodate=false;
						while(!uptodate){
							Key key=new KeyFactory.Builder(clientKey)
							.getKey();
							Entity service=new Entity("Service",key);
							service.setUnindexedProperty("CreatedBy", user.getNickname());
							service.setUnindexedProperty("CreatedDate", new Date(System.currentTimeMillis()));
							service.setUnindexedProperty("LastModifiedBy", user.getNickname());
							service.setUnindexedProperty("LastModifiedDate", new Date(System.currentTimeMillis()));
							service.setProperty("Client", clientKey);
							service.setProperty("Billed", Boolean.FALSE);
							service.setProperty("Type", type);
							service.setProperty("Completed", false);
							service.setProperty("Billable", billable);
							service.setUnindexedProperty("Fee", Double.parseDouble(fee));
							service.setProperty("Accountant", accountant);
							if(note!=null){
								service.setUnindexedProperty("Note", new Text(note));
							}
							service.setProperty("DueDate", nextDate.getTime());
							services.add(service);
							if(repeat.equalsIgnoreCase("monthly")){
								nextDate.add(Calendar.MONTH, 1);
							}else if(repeat.equalsIgnoreCase("quarterly")){
								nextDate.add(Calendar.MONTH, 3);
							}else{
								nextDate.add(Calendar.YEAR, 1);
							}
							if(nextDate.after(untilDate)){
								uptodate=true;
							}
						}
					}else{
						resp.getWriter().write("{\"success\":false,\"error\":\"Invalid until date\"}");
					}
				}else{
					if(times!=null&&Integer.parseInt(times)>1){
						Date tempDate=new Date(Long.parseLong(dueDateString));
						GregorianCalendar nextDate=new GregorianCalendar();
						nextDate.setTime(tempDate);
						int numberOfTime=Integer.parseInt(times);
						for(int i=0;i<numberOfTime;i++){
							Key key=new KeyFactory.Builder(clientKey)
							.getKey();
							Entity service=new Entity("Service",key);
							service.setUnindexedProperty("CreatedBy", user.getNickname());
							service.setUnindexedProperty("CreatedDate", new Date(System.currentTimeMillis()));
							service.setUnindexedProperty("LastModifiedBy", user.getNickname());
							service.setUnindexedProperty("LastModifiedDate", new Date(System.currentTimeMillis()));
							service.setProperty("Client", clientKey);
							service.setProperty("Billed", Boolean.FALSE);
							service.setProperty("Type", type);
							service.setProperty("Billable", billable);
							service.setProperty("Completed", false);
							service.setUnindexedProperty("Fee", Double.parseDouble(fee));
							service.setProperty("Accountant", accountant);
							if(note!=null){
								service.setUnindexedProperty("Note", new Text(note));
							}
							service.setProperty("DueDate", nextDate.getTime());
							services.add(service);
							if(repeat.equalsIgnoreCase("monthly")){
								nextDate.add(Calendar.MONTH, 1);
							}else if(repeat.equalsIgnoreCase("quarterly")){
								nextDate.add(Calendar.MONTH, 3);
							}else{
								nextDate.add(Calendar.YEAR, 1);
							}
						}
					}else{
						// No until and no times.
						resp.getWriter().write("{\"success\":false,\"error\":\"Invalid until or times\"}");
					}
				}
			}
			if(services!=null&&!services.isEmpty()){
				List<Key> keys=ClientDAO.saveClientServices(services);
				JSONObject response=new JSONObject();
				try {
					if(keys!=null&&!keys.isEmpty()){
						response.put("success", true);
						response.put("clientId", clientId);
						response.put("clientName", clientName);
					}else{
						response.put("success", false);
						response.put("clientId", clientId);
						response.put("clientName", clientName);
						response.put("error", "Unable to save client at the moment.");
					}
				} catch (JSONException e) {
					logger.severe(e.getMessage());
				}
				resp.getWriter().write(response.toString());
			}else{
				resp.getWriter().write("{\"success\":false,\"error\":\"Unable to add services at the moment, please try again later.\"}");
			}
		}
	}

}
